package plugin

import (
	"net/http"
	"os"
	"strings"
	"time"
	"webgo/server/util"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt"
)

type HttpserverType struct {
	Type[struct {
		Url              string `env:"HTTP_SERVER_URL"`
		File             string `env:"HTTP_SERVER_FILE"`
		Html             string `env:"HTTP_SERVER_HTML"`
		Jwtkey           string `env:"HTTP_SERVER_JWTKEY"`
		JwtkeyExpiryTime int64  `env:"HTTP_SERVER_JWTKEY_EXPIRY_TIME"`
	}]

	object *http.Server
	router *gin.Engine
}

type (
	HttpServerRouter = gin.Engine
)

var HTTP_RESPONSE_CODE = struct {
	SUCCESS      int // 成功
	FAIL         int // 失败
	ERROR        int // 错误
	INVISIBLE    int // 不可见
	UNAUTHORIZED int // 登录失效
}{SUCCESS: 200, FAIL: 201, ERROR: 202, INVISIBLE: 203, UNAUTHORIZED: 401}

func HttpResponse(ctx *gin.Context, code int, msg any, data any) {

	ctx.JSON(http.StatusOK, map[string]any{
		"msg":  msg,
		"code": code,
		"data": data,
	})
}

func (httpserver *HttpserverType) Init() (err error) {

	var (
		html_entry_names []string
	)

	gin.SetMode(gin.ReleaseMode)

	httpserver.router = gin.New()

	// httpserver.router.Use(gzip.Gzip(gzip.DefaultCompression))

	httpserver.router.Use(cors.New(cors.Config{
		AllowOrigins:     []string{"*"},
		AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		AllowHeaders:     []string{"*"},
		AllowCredentials: true,
	}))

	if html_entry_names, err = util.DirEntry(httpserver.config.Html); err != nil {
		return
	}

	httpserver.router.Static("/"+httpserver.config.File, httpserver.config.File)

	for _, html_entry_name := range html_entry_names {

		if html_entry_name == "index.html" {
			httpserver.router.StaticFile("/", httpserver.config.Html+"/index.html")

		} else {
			httpserver.router.Static("/"+html_entry_name, httpserver.config.Html+"/"+html_entry_name)
		}
	}

	httpserver.router.NoRoute(func(c *gin.Context) {
		c.File(httpserver.config.Html + "/index.html")
	})

	httpserver.object = &http.Server{
		Handler: httpserver.router,
	}

	return
}

func (httpserver *HttpserverType) Close() {

}

func (httpserver *HttpserverType) Running(callback func(router *HttpServerRouter)) {

	callback(httpserver.router)

	go func() {
		httpserver.router.Run(httpserver.config.Url)
		os.Exit(0)
	}()
}

type claims struct {
	ExpiryTime int64
	Id         MongoObjectId
	UpdateTime int64

	jwt.StandardClaims
}

func (httpserver *HttpserverType) TokenCompose(id MongoObjectId, update_time int64) (token string, err error) {

	var (
		claims = &claims{
			ExpiryTime: time.Now().Unix() + httpserver.config.JwtkeyExpiryTime,
			Id:         id,
			UpdateTime: update_time,
		}

		_token = jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	)

	token, err = _token.SignedString([]byte(httpserver.config.Jwtkey))

	token = "Bearer " + token

	return
}

func (httpserver *HttpserverType) TokenParse(token string) (id MongoObjectId, update_time int64, ok bool) {

	var (
		claims = &claims{}
	)

	token = strings.ReplaceAll(token, "Bearer ", "")

	if _, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (i interface{}, err error) {
		return []byte(httpserver.config.Jwtkey), nil
	}); err != nil {
		return
	}

	if time.Now().Unix() > claims.ExpiryTime {
		return
	}

	id = claims.Id
	update_time = claims.UpdateTime

	ok = true

	return
}
